import {
    transformAttribute,
    transformEvent
} from "./helper";
import {ASTParser} from "./ASTParser";
import {isDef} from "../../shared/util";

const DIRECTIVE_DETECTOR_REGEX = /^(v-|:|@)/;
const STATIC_EVENT_DETECTOR_REGEX = /^on/;
// 此处调整 v-else-if 应该比 v-else 在前
const DIRECTIVE_REGEX = /^(v-on:|v-bind:|:|@|v-pre|v-once|v-show|v-for|v-key|v-if|v-else-if|v-else|v-slot:)([^:@\s"'<>\/=]+)?$/;

// 将语法指令 翻译为 ASTNODE conditionBitMap 中对应的 key的值
const TRANSFORM_KEY = {
    "v-pre": "pre",
    "v-slot": "slotImplement",
    "v-once": "once",
    "v-for": "for",
    "v-key": "key",
    "v-show": "show",
    "v-if": "if",
    "v-else-if": "elseIf",
    "v-else": "else",
};

/**
 * 处理动态指令属性，并将对应的信息储存在 ASTNode 上（原本的对象是 HNode）
 * @param {{key: String, value: any}} attr
 * @param {ASTNode} astNode
 */
function parseDirectives (attr, astNode) {
    const key = attr.key;
    const matchResult = key.match(DIRECTIVE_REGEX);

    // 指令名称
    const directiveName = matchResult[1];
    // 被绑定的属性名称
    const propertyName = matchResult[2];
    // 被绑定在属性上的值
    const propertyValue = attr.value;

    switch (directiveName) {
        case ("v-bind:"):
        case (":"): {
            astNode.dynamicAttrList.push({
                key: propertyName,
                value: propertyValue
            });
            break;
        }
        case ("v-on:"):
        case ("@"): {
            astNode.dynamicEventList.push({
                key: propertyName,
                value: propertyValue
            });
            break;
        }
        // 这里不进行 指令的 语法检查
        // 原因是 HNode 中指令的顺序是乱序的，不是按照优先级排序的
        // 所以 这里只负责对指令内容的处理，但不做语法检查
        case ("v-slot:"): {
            astNode.conditionBitMap.slotImplement = true;
            astNode.conditionStrValueMap.slotImplement = {
                name: isDef(propertyName) ? propertyName : 'default',
                scope: propertyValue
            };
            break;
        }
        case ("v-pre"):
        case ("v-once"):
        case ("v-for"):
        case ("v-key"):
        case ("v-show"):
        case ("v-if"):
        case ("v-else-if"):
        case ("v-else"): {
            const transformKey = TRANSFORM_KEY[directiveName];
            if (!astNode.conditionBitMap[transformKey]) {
                astNode.conditionBitMap[transformKey] = true;
                astNode.conditionStrValueMap[transformKey] = propertyValue;
            }
            break;
        }
    }
}

/**
 * 处理静态属性，并将对应的信息储存在 ASTNode 上（原本的对象是 HNode）
 * @param {{key: String, value: any}} attr
 * @param {ASTNode} astNode
 */
function parseStatics (attr, astNode) {
    const key = attr.key;
    // 是事件
    if (STATIC_EVENT_DETECTOR_REGEX.test(key)) {
        astNode.staticEventList.push(attr);
    }
    // 是属性
    else {
        astNode.staticAttrList.push(attr);
    }
}

/**
 * 将 属性 List 转换为 Map
 * @param {ASTNode} astNode
 * @param {Boolean} isDynamic
 */
function generateAttributeMap (astNode, isDynamic) {
    // 获取属性列表
    let attrList = null;
    isDynamic
        ? attrList = astNode.dynamicAttrList
        : attrList = astNode.staticAttrList;
    // 处理事件
    attrList.forEach(attr => {
        transformAttribute(astNode, attr, isDynamic);
    })
}

/**
 * 将 事件 List 转换为 Map
 * @param {ASTNode} astNode
 * @param {Boolean} isDynamic
 */
function generateEventMap (astNode, isDynamic) {
    // 获取事件列表
    let eventList = null;
    isDynamic
        ? eventList = astNode.dynamicEventList
        : eventList = astNode.staticEventList;
    // 处理事件
    eventList.forEach(attr => {
       transformEvent(astNode, attr, isDynamic);
    });
}


/**
 * 处理 HNode 上的属性，并将其中的指令属性分离
 * @param {HNode} hNode
 */
export function parseProperty(hNode) {
    const attrs = hNode.attrsList;
    const astNode = hNode;

    // 扩展 hNode 的属性
    // List
    astNode.staticAttrList === undefined ? astNode.staticAttrList = new Array() : undefined;
    astNode.dynamicAttrList === undefined ? astNode.dynamicAttrList = new Array() : undefined;
    astNode.staticEventList === undefined ? astNode.staticEventList = new Array() : undefined;
    astNode.dynamicEventList === undefined ? astNode.dynamicEventList = new Array() : undefined;
    // Map
    astNode.staticAttrMap === undefined ? astNode.staticAttrMap = {} : undefined;
    astNode.dynamicAttrMap === undefined ? astNode.dynamicAttrMap = {} : undefined;
    astNode.staticEventMap === undefined ? astNode.staticEventMap = {} : undefined;
    astNode.dynamicEventMap === undefined ? astNode.dynamicEventMap = {} : undefined;

    // 解析属性，并对属性分类
    // 开始处理 Html 属性，将对应属性解析到以上四个数组中
    for (let i=0; i<attrs.length; i++) {
        // 动态属性解析
        if (DIRECTIVE_DETECTOR_REGEX.test(attrs[i].key)) {
            // 如果在 v-pre 作用域内，则不解析动态属性
            if (ASTParser.inPre) {
                continue;
            }
            astNode.isDynamic = true;
            parseDirectives(attrs[i], astNode);
        }
        // 静态属性解析
        else {
            parseStatics(attrs[i], astNode);
        }
    }

    // 对分类后的属性，将 List 转为 Map，便于后期处理
    // 同时对一些特殊的属性进行处理，比如 class, style
    // 如果不在 v-pre 作用域内，则对动态属性进行 List => Map
    if (!ASTParser.inPre) {
        generateAttributeMap(astNode, true);
        generateEventMap(astNode, true);
    }
    generateAttributeMap(astNode, false);
    generateEventMap(astNode, false);
}
